<template>
	<button @click="handleFileChange" :class="['upload-button', { uploading: uploading }]" :disabled="disabled">
		<template v-if="!uploading && !fileSelected">
			<slot>
				<view class="upload-icon">
					<text class="icon-upload"></text>
				</view>
				<view class="upload-text">
					{{ buttonText }}
				</view>
			</slot>
		</template>
		<template v-else>
			<view v-if="uploading" class="upload-progress">
				<slot name="loading" :progress="progress">
					<view class="progress-bar">
						<view class="progress-bar-filled" :style="{ width: `${progress}%` }"></view>
					</view>
					<view class="progress-text">{{ progress }}%</view>
				</slot>
			</view>
			<view v-else-if="fileSelected" class="selected-file">
				<slot name="selected-file" :file="selectedFile" :file-type="fileFormat" :file-size="fileSize">
					<view class="file-name">{{ selectedFile.name }}</view>
					<view class="file-info">{{ fileFormat }} {{ fileSize }}</view>
				</slot>
			</view>
		</template>
	</button>
</template>

<script setup lang="ts">
import { ref, computed, inject, watchEffect } from 'vue';

const props = defineProps({
	buttonText: {
		type: String,
		default: '上传文件'
	},
	accept: {
		type: String,
		default: '*'
	},
	disabled: {
		type: Boolean,
		default: false
	},
	uploadUrl: {
		type: String,
		required: true
	},
	toKen: {
		type: String,
		default: null
	},
	requestMode: {
		type: String,
		default: 'POST'
	}
});

const emit = defineEmits(['success', 'error', 'cancel']);

const config = inject<any>('config');
const selectedFile = ref(null);
const progress = ref<number>(0);
const uploading = ref<boolean>(false);
const fileSelected = ref<boolean>(false);

const fileFormat = computed(() => {
	if (selectedFile.value) {
		const name = selectedFile.value.name;
		const extension = name.split('.').pop().toLowerCase(); // 获取文件扩展名

		if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension)) {
			return '图片';
		}
		if (extension === 'pdf') {
			return 'PDF';
		}
		return '文件';
	}
	return '';
});

const fileSize = computed(() => {
	if (selectedFile.value) {
		const size = selectedFile.value.size;
		if (size < 1024) return `${size} B`;
		if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
		return `${(size / 1024 / 1024).toFixed(2)} MB`;
	}
	return '';
});

watchEffect(() => {
	if (props.disabled) {
		uploading.value = false;
	}
});
const handleFileChange = () => {
	if (typeof uni !== 'undefined') {
		// 使用 uni.chooseImage 选择图片
		uni.chooseImage({
			count: 1,
			sizeType: ['original', 'compressed'],
			sourceType: ['album', 'camera'],
			success: (res) => {
				const tempFilePath = res.tempFilePaths[0];
				selectedFile.value = { path: tempFilePath, name: tempFilePath.split('/').pop() };
				fileSelected.value = true;
				uploadFile(tempFilePath); // 直接传递文件路径
			},
			fail: (err) => {
				console.error('选择图片失败:', err);
			}
		});
	} else {
		// 浏览器环境使用 HTML File API
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = props.accept;
		input.onchange = (e) => {
			const files = e.target.files;
			if (files && files.length > 0) {
				selectedFile.value = files[0];
				fileSelected.value = true;
				uploadFile(files[0]);
			}
		};
		input.click();
	}
};

const uploadFile = (file) => {
	if (!file) return;
	uploading.value = true;
	progress.value = 0;

	if (typeof uni !== 'undefined') {
		// uni-app 环境
		const uploadTask = uni.uploadFile({
			url: props.uploadUrl,
			filePath: file,
			name: 'file',
			header: props.toKen
				? {
						Authorization: `Bearer ${props.toKen}`
				  }
				: {},
			formData: {},
			timeout: 60000, // 设置超时时间为60秒
			success: (res) => {
				emit('success', JSON.parse(res.data));
			},
			fail: (err) => {
				console.error('上传失败:', err);
				emit('error', err);
			},
			complete: () => {
				uploading.value = false;
			}
		});

		// 监听上传进度
		uploadTask.onProgressUpdate((res) => {
			progress.value = res.progress;
		});
	} else {
		// 浏览器环境
		const formData = new FormData();
		formData.append('file', file);

		const xhr = new XMLHttpRequest();
		xhr.open(props.requestMode, props.uploadUrl, true);
		if (props.toKen) {
			xhr.setRequestHeader('Authorization', `Bearer ${props.toKen}`);
		}

		xhr.upload.onprogress = (event) => {
			if (event.lengthComputable) {
				progress.value = (event.loaded / event.total) * 100;
			}
		};

		xhr.onload = () => {
			if (xhr.status >= 200 && xhr.status < 300) {
				emit('success', JSON.parse(xhr.responseText));
			} else {
				console.error('上传失败:', xhr.statusText);
				emit('error', { errMsg: '上传失败' });
			}
			uploading.value = false;
		};

		xhr.onerror = () => {
			console.error('上传出错:', xhr.statusText);
			emit('error', { errMsg: '上传出错' });
			uploading.value = false;
		};

		xhr.send(formData);
	}
};
</script>

<style lang="scss" scoped>
.upload-button {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 140rpx;
	border: 4rpx dashed;
	border-color: v-bind('config.border.color');
	border-radius: v-bind('config.borderRadius.semicircle');
	background-color: v-bind('config.VUploadFileButton.backgroundColor');
	color: v-bind('config.fontColor.mainText');
	cursor: pointer;
	transition: all 0.3s;

	&:hover {
		border-color: v-bind('config.border.default');
		background-color: v-bind('config.VUploadFileButton.backgroundColor');
		color: v-bind('config.fontColor.default');
	}

	&:disabled {
		cursor: not-allowed;
		opacity: 0.6;
	}

	&.uploading {
		border-color: v-bind('config.border.default');
		background-color: v-bind('config.VUploadFileButton.backgroundColor');
		color: v-bind('config.fontColor.default');
	}

	.upload-icon {
		margin-bottom: 8rpx;
		.icon-upload {
			font-size: v-bind('config.fontSize.mediumText');
		}
	}

	.upload-text {
		font-size: v-bind('config.fontSize.mediumText');
	}

	.upload-progress {
		width: 100%;
		text-align: center;
	}

	.progress-bar {
		width: 100%;
		height: 16rpx;
		background-color: v-bind('config.VUploadFileButton.backgroundColor');
		border-radius: 4rpx;
		overflow: hidden;
		margin-bottom: 8rpx;
	}

	.progress-bar-filled {
		height: 100%;
		background-color: v-bind('config.backgroundColor.default');
		width: 0;
		transition: width 0.3s;
	}

	.progress-text {
		font-size: v-bind('config.fontSize.mediumText');
		color: v-bind('config.fontColor.default');
	}

	.selected-file {
		width: 100%;
		text-align: center;
	}

	.file-name {
		font-size: v-bind('config.fontSize.mediumText');
		margin-bottom: 6rpx;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.file-info {
		font-size: v-bind('config.fontSize.mediumText');
		color: v-bind('config.fontColor.info');
	}
}
</style>
